package com.jie.common.ssl.util;

import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.symmetric.AES;
import com.jie.common.exception.constant.ExceptionMessageConstant;
import com.jie.common.exception.entity.JieException;
import com.jie.common.message.constant.MessageConstant;
import com.jie.common.util.BytesUtil;

import javax.crypto.SecretKey;
import java.security.SecureRandom;

/**
 * 用于对称加密(aes算法)的工具类
 * @author XieZhiJie
 * @date 2022/04/21 15:46
 */
public class AesUtil {

    /**
     * 解密并验证信息是否被破坏
     * @param encrypt 加密的数据
     * @param aes     AES对象
     * @param flag    是否启用了SSL
     * @return        返回解密后的数据
     */
    public static byte[] decryptAndVerifyDigest(byte[] encrypt, AES aes, boolean flag) throws JieException {
        if (flag) {
            byte[] decryptBytes = aes.decrypt(encrypt);
            int originalBytesLength = BytesUtil.transformBytesToInt(decryptBytes);
            byte[] originalBytes = new byte[originalBytesLength];
            byte[] digestBytes = new byte[decryptBytes.length - MessageConstant.MESSAGE_HEAD_LENGTH - originalBytesLength];
            System.arraycopy(decryptBytes, MessageConstant.MESSAGE_HEAD_LENGTH, originalBytes, 0, originalBytesLength);
            System.arraycopy(decryptBytes, MessageConstant.MESSAGE_HEAD_LENGTH + originalBytesLength, digestBytes, 0, decryptBytes.length - MessageConstant.MESSAGE_HEAD_LENGTH - originalBytesLength);
            if (BytesUtil.compareBytesAndBytesArray(DigestUtil.generateDigest(originalBytes), digestBytes)) {
                return originalBytes;
            }
            throw new JieException(ExceptionMessageConstant.MESSAGE_VERIFY_FAIL);
        }
        return encrypt;
    }

    /**
     * 添加摘要并加密
     * @param original 原字节数组
     * @param aes      AES对象
     * @param flag     是否启用了SSL
     * @return         返回了 MessageConstant.MESSAGE_HEAD_LENGTH字节记录原字节数组长度 + 原字节数组 + 摘要
     */
    public static byte[] addDigestAndEncrypt(byte[] original, AES aes, boolean flag) {
        return flag ? encrypt(DigestUtil.addDigest(original), aes) :  original;
    }

    /**
     * 用AES对象解密密文
     * @param encrypt 密文
     * @param aes     AES对象
     * @return        返回解密后的字节数组
     */
    public static byte[] decrypt(byte[] encrypt, AES aes) {
        return aes.decrypt(encrypt);
    }

    /**
     * 用AES对象加密原文
     * @param original 原文
     * @param aes      AES对象
     * @return         返回加密后的字节数组
     */
    public static byte[] encrypt(byte[] original, AES aes) {
        return aes.encrypt(original);
    }

    /**
     * 根据三个字节数组生成一个会话密钥
     * @param x 字节数组x
     * @param y 字节数组y
     * @param z 字节数组z
     * @return  返回生成的会话密钥
     */
    public static byte[] generateSessionKey(byte[] x, byte[] y, byte[] z) {
        byte[] seedBytes = new byte[x.length + y.length + z.length];
        int offset = 0;
        System.arraycopy(x, 0, seedBytes, offset, x.length);
        offset += x.length;
        System.arraycopy(y, 0, seedBytes, offset, y.length);
        offset += y.length;
        System.arraycopy(z, 0, seedBytes, offset, z.length);
        seedBytes = cn.hutool.crypto.digest.DigestUtil.sha1(seedBytes);
        SecureRandom secureRandom = new SecureRandom(seedBytes);
        SecretKey aesKey = KeyUtil.generateKey("AES", -1, secureRandom);
        return aesKey.getEncoded();
    }

}
